BlazeDS のログを Log4j で制御して出力したい
Javaでログ出力するなら Apache log4j を使いたくなります。AMF通信やサーバプッシュで有名な BlazeDS において、この Log4j を使おうと思っても標準機能では上手くいきません。
BlazeDS には flex.messaging.log パッケージにある AbstractTarget クラスを基底とする独自のロギングの仕組みが提供されています。そしてこれらの設定は WEB-INF/flex/services-config.xml で定義されています。
<services-config> (・・・省略・・・) <logging> <target class="flex.messaging.log.ConsoleTarget" level="INFO"> <properties> <prefix>[BlazeDS] </prefix> <includeDate>true</includeDate> <includeTime>true</includeTime> <includeLevel>true</includeLevel> <includeCategory>true</includeCategory> </properties> <filters> </filters> </target> </logging> </services-config>
標準のコンソール出力は上記のとおりです。要するに Log4j で出力するターゲットクラスを作って指定すれば、期待する実装が可能になります。
そしていきなりですが、作成したクラスは下記のとおりになります。flex.messaging.log.LineFormattedTarget クラスをベースに、ログレベルとタイムスタンプの機能を除いて作りました。これらは Log4j で制御するためです。
package jp.cm.log; import org.apache.log4j.Logger; import flex.messaging.log.AbstractTarget; import flex.messaging.log.LogEvent; import flex.messaging.config.ConfigMap; import flex.messaging.util.ExceptionUtil; import flex.messaging.util.StringUtils; public class BlazeLog4jTarget extends AbstractTarget { protected Logger logger = Logger.getRootLogger(); protected boolean includeCategory; protected String prefix = null; public BlazeLog4jTarget() { super(); } /** * Initializes the target with id and properties. Subclasses can overwrite. * * @param id * id for the target which is ignored. * @param properties * ConfigMap of properties for the target. */ public void initialize(String id, ConfigMap properties) { super.initialize(id, properties); includeCategory = properties.getPropertyAsBoolean("includeCategory", false); prefix = properties.getPropertyAsString("prefix", null); } /** * Returns includeCategory property. * * @return <code>true</code> if category is included; <code>false</code> * otherwise. */ public boolean isIncludeCategory() { return includeCategory; } /** * Sets includeCategory property. * * @param includeCategory */ public void setIncludeCategory(boolean includeCategory) { this.includeCategory = includeCategory; } /** * Returns prefix property. * * @return The prefix for log messages. */ public String getPrefix() { return prefix; } /** * Sets prefix property. * * @param prefix */ public void setPrefix(String prefix) { this.prefix = prefix; } /** * This method handles a <code>LogEvent</code> from an associated logger. A * target uses this method to translate the event into the appropriate * format for transmission, storage, or display. This method will be called * only if the event's level is in range of the target's level. */ @Override public void logEvent(LogEvent event) { StringBuffer result = new StringBuffer(); if (prefix != null) { result.append(prefix); } if (includeCategory) { result.append("[" + event.logger.getCategory() + "] "); } result.append(event.message); if (event.throwable != null) { result.append(StringUtils.NEWLINE).append( ExceptionUtil.toString(event.throwable)); } switch (event.level) { case LogEvent.ALL: if (logger.isTraceEnabled()) { logger.trace(result.toString()); } case LogEvent.DEBUG: if (logger.isDebugEnabled()) { logger.debug(result.toString()); } break; case LogEvent.INFO: if (logger.isInfoEnabled()) { logger.debug(result.toString()); } break; case LogEvent.WARN: logger.warn(result.toString()); break; case LogEvent.ERROR: logger.error(result.toString()); break; case LogEvent.FATAL: logger.fatal(result.toString()); break; } } }
この BlazeLog4JTarget クラスを定義する services-config.xml は下記のようになります。
<services-config> <logging> <target class="jp.cm.log.BlazeLog4jTarget" level="INFO"> <properties> <prefix>[BlazeDS] </prefix> <includeCategory>true</includeCategory> </properties> <filters> </filters> </target> </logging> </services-config>